home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume13 / cfc < prev    next >
Encoding:
Internet Message Format  |  1988-01-31  |  24.3 KB

  1. Subject:  v13i030:  New version of .cf compiler
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: "Arnold D. Robbins" <arnold@EMORYU1.ARPA>
  7. Posting-number: Volume 13, Issue 30
  8. Archive-name: cfc
  9.  
  10. [  CFC is a program that turns sendmail.cf files into almost directly-
  11.    readable EASE language files.  I wrote the Makefile and just slipped
  12.    it into the shar.  --r$ ]
  13.  
  14. Rich,
  15.     I think the only BSD-ism is the use of index.
  16.  
  17. Arnold Robbins
  18. The (wounded and bleeding) slayer of Sendmail dragons
  19.  
  20. #! /bin/sh
  21. # This is a shell archive, meaning:
  22. # 1. Remove everything above the #! /bin/sh line.
  23. # 2. Save the resulting text in a file.
  24. # 3. Execute the file with /bin/sh (not csh) to create the files:
  25. #    Makefile
  26. #    cfc.1
  27. #    cfc.c
  28. export PATH; PATH=/bin:$PATH
  29. echo shar: extracting "'Makefile'" '(some number of characters)'
  30. if test -f 'Makefile'
  31. then
  32.     echo shar: will not over-write existing file "'Makefile'"
  33. else
  34. cat << \SHAR_EOF > 'Makefile'
  35. all:        cfc cfc.1
  36. install:    all
  37.     @echo install according to local conventions.
  38. cfc:        cfc.c
  39.     $(CC) $(CFLAGS) -o cfc cfc.c
  40. SHAR_EOF
  41. fi # end of overwriting check
  42.  
  43. echo shar: extracting "'cfc.1'" '(3162 characters)'
  44. if test -f 'cfc.1'
  45. then
  46.     echo shar: will not over-write existing file "'cfc.1'"
  47. else
  48. cat << \SHAR_EOF > 'cfc.1'
  49. ...
  50. ... $Header: cfc.1,v 1.3 88/01/21 16:23:21 arnold Locked $
  51. ... 
  52. ... $Log:    cfc.1,v $
  53. ... Revision 1.3  88/01/21  16:23:21  arnold
  54. ... Some typo fixes.
  55. ... 
  56. ... Revision 1.2  87/04/08  10:21:47  arnold
  57. ... Small bug fixes, compatibility option added, also warnings for
  58. ... unrecognized flags and options. ADR.
  59. ... 
  60. ... Revision 1.1  87/02/16  15:25:32  arnold
  61. ... Initial revision
  62. ... 
  63. ...
  64. .TH CFC 8 local
  65. .SH NAME
  66. cfc \- Sendmail cf file compiler
  67. .SH SYNOPSIS
  68. .B cfc
  69. [
  70. .B \-c
  71. ] <
  72. .I sendmail.cf-file
  73. >
  74. .I ease-source-file
  75. .SH DESCRIPTION
  76. .I Cfc
  77. is a filter that reads a raw
  78. .IR sendmail (8)
  79. configuration file on its standard input, and produces almost useable
  80. .IR ease (1)
  81. source on its standard output.
  82. .P
  83. It is designed as a conversion tool, to translate an existing
  84. .B sendmail.cf
  85. file into
  86. .I ease
  87. with the idea that all future work will be done in
  88. .IR ease .
  89. .P
  90. .I Cfc
  91. passes all comments through to the output, and converts all predefined
  92. .I sendmail
  93. macros, options, option values, and mailer flags into the names used by
  94. .IR ease .
  95. .P
  96. Once it is through, the user need only spend some time in a good screen
  97. editor doing the following:
  98. .RS
  99. .P
  100. Changing the RULESET_n names into more descriptive names, and
  101. adding ruleset bindings.
  102. .P
  103. Applying quoting to necessary string literals, principally in the
  104. definitions of headers. The
  105. .I ease
  106. documentation on header formats should be consulted.
  107. .P
  108. Adding new field names.
  109. .I Cfc
  110. just uses very generic field names, everywhere, when names like ``user,''
  111. ``host,'' and ``relay'' might be more descriptive.
  112. .P
  113. Miscellanious formatting.
  114. .I Cfc
  115. introduces tabs on its own, as well as often passing through tabs
  116. from the
  117. .I sendmail
  118. input.
  119. It will also print a header for each different type of line, e.g. if the
  120. input had seven
  121. .B O
  122. (option) lines, there will be seven option blocks.
  123. These are usually succesive, and can therefore be merged.
  124. Finally, the block close on rulesets often comes after the comments that
  125. precede the next ruleset or mailer specification.
  126. .RE
  127. .P
  128. In short,
  129. .I cfc
  130. does over 90% of the tedious work of translating a
  131. .B sendmail.cf
  132. into
  133. .I ease
  134. format.
  135. The rest of the work can be done in a day or less.
  136. Suprisingly, the combination of
  137. .I cfc
  138. and
  139. .I ease
  140. can find bugs in a current
  141. .B sendmail.cf
  142. file!
  143. .P
  144. .I Cfc takes one option,
  145. .BR \-c ,
  146. which indicates it should run in 4.2BSD compatibility mode.
  147. In this case, options and mailer flags which are new in the 4.3BSD
  148. version of
  149. .I sendmail
  150. will not be recognized.
  151. .\" .SH FILES
  152. .SH SEE ALSO
  153. .I "Sendmail Installation and Operation Guide"
  154. by Eric Allman
  155. (SMM:7 in the 4.3 BSD UNIX System Manager's Manual),
  156. .I "Ease: A Configuration Language for Sendmail"
  157. by James S. Schoner,
  158. .IR sendmail (8),
  159. .IR ease (1).
  160. .SH DIAGNOSTICS
  161. ``\c
  162. .IR Routine :
  163. malformed input line
  164. .IR line :
  165. fatal error''
  166. for input it doesn't understand.
  167. .I Routine
  168. is the name of the routine in
  169. .I cfc
  170. which choked, and
  171. .I line
  172. is the line number in the input.
  173. .SH BUGS
  174. Only recognizes continuation lines (lines that begin with a \s-1TAB\s+1)
  175. for header (H) and mailer (M) definitions.
  176. .SH AUTHOR
  177. .nf
  178. Arnold Robbins
  179. Emory University Computing Center
  180. arnold@emory.edu
  181. .fi
  182. SHAR_EOF
  183. fi # end of overwriting check
  184. echo shar: extracting "'cfc.c'" '(20180 characters)'
  185. if test -f 'cfc.c'
  186. then
  187.     echo shar: will not over-write existing file "'cfc.c'"
  188. else
  189. cat << \SHAR_EOF > 'cfc.c'
  190. #ifndef lint
  191. static char RCSid[] = "$Header: cfc.c,v 1.5 88/01/21 16:18:13 root Locked $";
  192. #endif
  193.  
  194. /*
  195.  * $Log:    cfc.c,v $
  196.  * Revision 1.5  88/01/21  16:18:13  root
  197.  * Eliminated Rutgers-ism, linted, smartened Mailer Argv handling. ADR.
  198.  * 
  199.  * Revision 1.4  88/01/21  15:57:52  root
  200.  * Added the 'y' factor; missed it last time. ADR.
  201.  * 
  202.  * Revision 1.3  87/04/08  10:23:02  root
  203.  * Small bug fixes, compatibility option added, also warnings for
  204.  * unrecognized flags and options. ADR.
  205.  * 
  206.  * Revision 1.2  87/02/18  15:26:39  root
  207.  * Fix to recognize multidigit ruleset numbers in $> (calls) in RHS. ADR.
  208.  * 
  209.  * Revision 1.1  87/02/16  15:25:00  arnold
  210.  * Initial revision
  211.  * 
  212.  * Revision 1.1  87/02/16  15:25:00  arnold
  213.  * Initial revision
  214.  * 
  215.  */
  216.  
  217. /*
  218.  * cfc.c
  219.  *
  220.  * Sendmail cf file compiler.
  221.  * Reads a raw sendmail.cf file and produces ease source.
  222.  *
  223.  * There are very few comments in this source. You will need both the
  224.  * "Sendmail Installation and Operation Guide" and the paper on Ease
  225.  * to really understand this.
  226.  *
  227.  * Arnold Robbins
  228.  * Emory University Computing Center
  229.  * 2/87
  230.  */
  231.  
  232. #include <stdio.h>
  233. #include <ctype.h>
  234.  
  235. char buffer[BUFSIZ];
  236. int line = 0;
  237. int inruleset = 0;
  238.  
  239. extern char *macro ();        /* convert sendmail to ease macro names */
  240. extern char *mflags ();        /* convert sendmail to ease mailer flag names */
  241. extern char *optionname ();    /* convert sendmail to ease option names */
  242. extern char *delivoption ();    /* delivery options */
  243. extern char *handle_option ();    /* handling options */
  244.  
  245. extern char *ngets ();        /* buffered gets () routine */
  246. extern void ungets ();        /* put a buffer back for getting */
  247.  
  248. #define endruleset()    if (inruleset) { inruleset = 0; printf ("\t}\n"); }
  249.  
  250. int compat = 0;            /* complain about new 4.3 options & flags */
  251.  
  252. main (argc, argv)
  253. int argc;
  254. char **argv;
  255. {
  256.     if (argc > 1)
  257.     {
  258.         if (strcmp (argv[1], "-c") == 0)
  259.             compat = 1;
  260.         else
  261.         {
  262.             fprintf (stderr, "usage: %s [ -c ]\n", argv[0]);
  263.             fprintf (stderr, "illegal argument '%s' ignored\n",
  264.                     argv[1]);
  265.         }
  266.     }
  267.  
  268.     printf ("/******************************************************/\n");
  269.     printf ("/* This ease file generated by cfc from a sendmail.cf */\n");
  270.     printf ("/* file. It must be edited by hand before being fed   */\n");
  271.     printf ("/* to ease!                                           */\n");
  272.     printf ("/******************************************************/\n");
  273.     printf ("\n\nbind\n\t/* RULESET BINDINGS GO HERE (cfc) */\n\n");
  274.  
  275.     /*
  276.      * For perfection, everything but the comment and rule cases
  277.      * should do an endruleset (), but practically speaking, it is
  278.      * usually only the mailer new ruleset definitions that end a
  279.      * previous ruleset. Occasionally a macro, too.
  280.      */
  281.  
  282.     while (ngets (buffer) != NULL)
  283.     {
  284.         line++;
  285.         switch (buffer[0]) {
  286.         case '#':
  287.             comment ();
  288.             continue;    /* skip code to end ruleset */
  289.         case 'S':
  290.             endruleset ();
  291.             ruleset ();
  292.             continue;    /* skip code to end ruleset */
  293.         case 'R':
  294.             rule ();
  295.             continue;    /* skip code to end ruleset */
  296.         case 'D':
  297.             endruleset ();
  298.             def ();
  299.             break;
  300.         case 'C':
  301.             class ();
  302.             break;
  303.         case 'F':
  304.             fileclass ();
  305.             break;
  306.         case 'M':
  307.             endruleset ();
  308.             mailer ();
  309.             break;
  310.         case 'H':
  311.             header ();
  312.             break;
  313.         case 'O':
  314.             option ();
  315.             break;
  316.         case 'T':
  317.             trusted ();
  318.             break;
  319.         case 'P':
  320.             precedence ();
  321.             break;
  322.         default:
  323.             other ();
  324.             continue;    /* skip code to end ruleset */
  325.         }
  326.         endruleset ();
  327.     }
  328.     endruleset ();        /* just in case */
  329.     exit (0);
  330.     /*NOTREACHED*/
  331. }
  332.  
  333. /* comment --- produce a comment */
  334.  
  335. comment ()
  336. {
  337.     static char format[] = "/* %s */\n";
  338.     register int i = strlen (buffer) - 1;
  339.  
  340.     /* try to be semi-intelligent about comments */
  341.  
  342.     if (buffer[1] == '\0')
  343.         printf ("\n");
  344.     else if (isspace (buffer[1]) && buffer[i] != '#')
  345.     {
  346.         for (i = 1; isspace (buffer[i]); i++)
  347.             ;
  348.         printf (format, buffer + i);
  349.     }
  350.     else
  351.         printf (format, buffer);
  352. }
  353.  
  354. /* ruleset --- name a ruleset */
  355.  
  356. ruleset ()
  357. {
  358.     static int first = 1;
  359.     register char *cp = buffer + 1;
  360.  
  361.     if (first)
  362.     {
  363.         first = 0;
  364.         printf ("\n/* These are sample field definitons (cfc) */\n");
  365.         printf ("\nfield\n\tzero_or_more : match (0*);\n");
  366.         printf ("\tone_or_more : match (1*);\n");
  367.         printf ("\texactly_one : match (1);\n");
  368.         printf ("\tany_in_? : match (1) in ?;\n");
  369.         printf ("\tany_not_in_? : match (0) in ?;\n\n");
  370.     }
  371.  
  372.     printf ("ruleset\n\tRULESET_");
  373.     while (*cp && ! isspace (*cp))
  374.     {
  375.         putchar (*cp);
  376.         cp++;
  377.     }
  378.  
  379.     printf (" {");
  380.     if (*cp)
  381.         printf ("\t/* %s */", cp);
  382.     putchar ('\n');
  383.     inruleset++;
  384. }
  385.  
  386. /* rule --- print out a rule */
  387.  
  388. rule ()
  389. {
  390.     register char *cp = buffer + 1;
  391.     register char *cp2;
  392.     register int com = 0;
  393.  
  394.     /* first, split it up into LHS, RHS, COMMENT */
  395.  
  396.     while (*cp != '\t')
  397.         cp++;
  398.     *cp = '\0';
  399.  
  400.     cp++;
  401.     while (*cp == '\t')
  402.         cp++;
  403.     cp2 = cp;
  404.     while (*cp && *cp != '\t')
  405.         cp++;
  406.     if (*cp == '\t' && cp[1])
  407.     {
  408.         *cp = '\0';
  409.         com++;
  410.         cp++;
  411.         while (*cp == '\t')
  412.             cp++;
  413.     }
  414.  
  415.     /* now print */
  416.     lhs (buffer + 1);    /* left hand side */
  417.     if (com)
  418.         printf ("\t/* %s */", cp);
  419.     putchar ('\n');
  420.     rhs (cp2);        /* right hand side */
  421. }
  422.  
  423. /* lhs --- left hand side of a production */
  424.  
  425. lhs (text)
  426. char *text;
  427. {
  428.     register char *cp = text;
  429.     register int conditional = 0;
  430.     register int quoting = 0;
  431.  
  432.     printf ("\tif (");
  433.     for (; *cp; cp++)
  434.     {
  435.         switch (*cp) {
  436.         case '$':
  437.             if (quoting)
  438.             {
  439.                 quoting = 0;
  440.                 putchar ('"');
  441.             }
  442.             switch (*++cp) {
  443.             case '*':
  444.                 printf (" zero_or_more ");
  445.                 break;
  446.             case '+':
  447.                 printf (" one_or_more ");
  448.                 break;
  449.             case '-':
  450.                 printf (" exactly_one ");
  451.                 break;
  452.             case '=':
  453.                 printf (" any_in_%c ", *++cp);
  454.                 break;
  455.             case '~':
  456.                 printf (" any_not_in_%c ", *++cp);
  457.                 break;
  458.             case '?':
  459.                 printf (" ifset (%s, ", macro (*++cp));
  460.                 conditional++;
  461.                 break;
  462.             case '|':
  463.                 printf (", ");
  464.                 break;
  465.             case '.':
  466.                 putchar (')');
  467.                 conditional--;
  468.                 break;
  469.             case '1':
  470.             case '2':
  471.             case '3':
  472.             case '4':
  473.             case '5':
  474.             case '6':
  475.             case '7':
  476.             case '8':
  477.             case '9':
  478.                 printf ("$%c", *cp);
  479.                 break;
  480.             default:
  481.                 if (quoting)
  482.                     printf ("${%s}", macro (*cp));
  483.                 else
  484.                     printf ("$%s", macro (*cp));
  485.                 break;
  486.             }
  487.             break;
  488.         default:
  489.             if (ispunct (*cp))
  490.             {
  491.                 if (quoting)    /* end a literal */
  492.                 {
  493.                     quoting = 0;
  494.                     putchar ('"');
  495.                 }
  496.                 /* else
  497.                     do nothing */
  498.             }
  499.             else
  500.             {
  501.                 if (! quoting)    /* start a literal */
  502.                 {
  503.                     quoting = 1;
  504.                     putchar ('"');
  505.                 }
  506.                 /* else
  507.                     do nothing */
  508.             }
  509.             putchar (*cp);    /* print the character */
  510.             break;
  511.         }
  512.     }
  513.     if (quoting)
  514.         putchar ('"');
  515.     if (conditional)
  516.         die ("lhs");
  517.     printf (")");
  518. }
  519.  
  520. /* rhs --- right hand side of a production */
  521.  
  522. rhs (text)
  523. char *text;
  524. {
  525.     register char *cp = text;
  526.     char *index ();
  527.     register int open = 0;
  528.     register int conditional = 0;
  529.     register int quoting = 0;
  530.  
  531.     printf ("\t\t");
  532.  
  533.     if (*cp == '$' && index ("#@:", cp[1]) != NULL)
  534.         ;    /* not the default */
  535.     else
  536.     {
  537.         printf ("retry (");
  538.         open++;
  539.     }
  540.  
  541.     for (; *cp; cp++)
  542.     {
  543.         switch (*cp) {
  544.         case '$':
  545.             if (quoting)
  546.             {
  547.                 quoting = 0;
  548.                 putchar ('"');
  549.             }
  550.             switch (*++cp) {
  551.             case '>':
  552.                 printf ("RULESET_");
  553.                 for (cp++; *cp && isdigit (*cp); cp++)
  554.                     putchar (*cp);
  555.                 cp--;
  556.                 printf (" (");
  557.                 open++;
  558.                 break;
  559.             case '[':
  560.                 printf ("canon (");
  561.                 open++;
  562.                 break;
  563.             case ']':
  564.                 putchar (')');
  565.                 open--;
  566.                 break;
  567.             case '?':
  568.                 printf ("ifset (%s, ", macro (*++cp));
  569.                 conditional++;
  570.                 break;
  571.             case '|':
  572.                 putchar (',');
  573.                 break;
  574.             case '.':
  575.                 putchar (')');
  576.                 conditional--;
  577.                 break;
  578.             case '#':
  579.                 printf ("resolve (mailer (");
  580.                 if (strncmp (cp+1, "local$", 6) == 0
  581.                     || strncmp (cp+1, "error$", 6) == 0)
  582.                     goto skiphost;
  583.             loop1:
  584.                 for (cp++; *cp != '$'; cp++)
  585.                     putchar (*cp);
  586.                 cp++;
  587.                 if (*cp != '@')
  588.                 {
  589.                     printf ("$%c", *cp);
  590.                     goto loop1;
  591.                 }
  592.                 printf ("),\n\t\t\t\thost (");
  593.             skiphost:
  594.             loop2:
  595.                 for (cp++; *cp != '$'; cp++)
  596.                     putchar (*cp);
  597.                 cp++;
  598.                 if (*cp != ':')
  599.                 {
  600.                     printf ("$%c", *cp);
  601.                     goto loop2;
  602.                 }
  603.                 printf ("),\n\t\t\t\tuser (");
  604.                 for (cp++; *cp; cp++)
  605.                     putchar (*cp);
  606.                 printf ("))");
  607.                 goto out;    /* string is exhausted */
  608.                 /* break; */
  609.             case '@':
  610.                 printf ("return (");
  611.                 open++;
  612.                 break;
  613.             case ':':
  614.                 printf ("next (");
  615.                 open++;
  616.                 break;
  617.             case '1':
  618.             case '2':
  619.             case '3':
  620.             case '4':
  621.             case '5':
  622.             case '6':
  623.             case '7':
  624.             case '8':
  625.             case '9':
  626.                 printf ("$%c", *cp);
  627.                 break;
  628.             default:
  629.                 if (quoting)
  630.                     printf ("${%s}", macro (*cp));
  631.                 else
  632.                     printf ("$%s", macro (*cp));
  633.                 break;
  634.             }
  635.             break;
  636.         default:
  637.             if (ispunct (*cp))
  638.             {
  639.                 if (quoting)    /* end a literal */
  640.                 {
  641.                     quoting = 0;
  642.                     putchar ('"');
  643.                 }
  644.                 /* else
  645.                     do nothing */
  646.             }
  647.             else
  648.             {
  649.                 if (! quoting)    /* start a literal */
  650.                 {
  651.                     quoting = 1;
  652.                     putchar ('"');
  653.                 }
  654.                 /* else
  655.                     do nothing */
  656.             }
  657.             putchar (*cp);    /* print the character */
  658.             break;
  659.         }
  660.     }
  661. out:
  662.     if (quoting)
  663.         putchar ('"');
  664.     while (open--)
  665.         putchar (')');
  666.     printf (";\n");
  667.     if (conditional)
  668.         die ("rhs");
  669. }
  670.  
  671. /* def --- define a macro */
  672.  
  673. def ()
  674. {
  675.     register char *mac = buffer + 1, *value = buffer + 2;
  676.     register int conditional = 0;
  677.  
  678.     printf ("macro\n\t%s = \"", macro (*mac));
  679.  
  680.     while (*value)
  681.     {
  682.         switch (*value) {
  683.         case '$':
  684.             switch (*++value) {
  685.             case '?':
  686.                 printf ("ifset (%s, ", macro (*++value));
  687.                 conditional++;
  688.                 break;
  689.             case '|':
  690.                 putchar (',');
  691.                 break;
  692.             case '.':
  693.                 putchar (')');
  694.                 conditional--;
  695.                 break;
  696.             default:
  697.                 printf ("${%s}", macro (*value));
  698.                 break;
  699.             }
  700.             break;
  701.         default:
  702.             putchar (*value);
  703.             break;
  704.         }
  705.         value++;
  706.     }
  707.     printf ("\";\n");
  708.     if (conditional)
  709.         die ("def");
  710. }
  711.  
  712. /* class --- define a class list */
  713.  
  714. class ()
  715. {
  716.     register char *name = buffer + 1, *value = buffer + 2;
  717.  
  718.     printf ("class\n\t%c = { ", *name);
  719.  
  720.     while (*value && isspace (*value))
  721.         value++;
  722.  
  723.     while (*value)
  724.     {
  725.         if (isspace (*value))
  726.         {
  727.             printf (", ");
  728.             while (isspace (*value))
  729.                 value++;
  730.             value--;    /* cancel loop */
  731.         }
  732.         else
  733.             putchar (*value);
  734.         value++;
  735.     }
  736.     printf (" };\n");
  737. }
  738.  
  739. /* fileclass --- define a class that is to be read from a file */
  740.  
  741. fileclass ()
  742. {
  743.     register char *name = buffer + 1, *value = buffer + 2;
  744.  
  745.     printf ("class\n\t%c = readclass (\"", *name);
  746.     for (; *value && !isspace (*value); value++)
  747.         putchar (*value);
  748.     putchar ('"');
  749.     while (*value && isspace (*value))
  750.         value++;
  751.     if (*value)
  752.         printf (", \"%s\"", value);
  753.     printf (");\n");
  754. }
  755.  
  756. /* mailer --- convert a mailer specification */
  757.  
  758. mailer ()
  759. {
  760.     register char *cp = buffer + 1;
  761.  
  762.     printf ("mailer\n\t");
  763.     for (; *cp != ','; cp++)
  764.         putchar (*cp);
  765.     cp++;
  766.     printf (" {\n");    /* just did mailer name */
  767.  
  768. #define skipname()    cp++; while (*cp != '=') cp++; cp++
  769. #define value()        for (; *cp && *cp != ','; cp++) putchar (*cp); cp++
  770.  
  771. loop:
  772.     while (*cp && isspace (*cp))
  773.         cp++;
  774.  
  775.     printf ("\t\t");
  776.     switch (*cp) {
  777.     case 'A':
  778.         skipname ();
  779.         printf ("Argv = \"");
  780.         for (; *cp && *cp != ','; cp++)
  781.         {
  782.             if (*cp == '$')    /* XXX: assume no conditionals */
  783.                 printf ("${%s}", macro (*++cp));
  784.             else if (*cp == '"')
  785.                 printf ("\\\"");
  786.             else
  787.                 putchar (*cp);
  788.         }
  789.         cp++;    /* do manually what value does */
  790.         putchar ('"');
  791.         break;
  792.  
  793.     case 'E':
  794.         skipname ();
  795.         printf ("Eol = \"");
  796.         value ();
  797.         putchar ('"');
  798.         break;
  799.  
  800.     case 'F':
  801.         skipname ();
  802.         printf ("Flags = { ");
  803.         for (; *cp && *cp != ','; cp++)
  804.         {
  805.             printf ("%s", mflags (*cp));
  806.             if (cp[1] && cp[1] != ',')
  807.                 printf (", ");
  808.         }
  809.         cp++;    /* do manually what value does */
  810.         printf (" }");
  811.         break;
  812.  
  813.     case 'M':
  814.         skipname ();
  815.         printf ("Maxsize = \"");
  816.         value ();
  817.         putchar ('"');
  818.         break;
  819.  
  820.     case 'P':
  821.         skipname ();
  822.         printf ("Path = \"");
  823.         value ();
  824.         putchar ('"');
  825.         break;
  826.  
  827.     case 'R':
  828.         skipname ();
  829.         printf ("Recipient = RULESET_");
  830.         value ();
  831.         break;
  832.  
  833.     case 'S':
  834.         skipname ();
  835.         printf ("Sender = RULESET_");
  836.         value ();
  837.         break;
  838.  
  839.     case '\0':
  840.         goto done;
  841.     }
  842.  
  843.     if (cp[-1] && cp[-1] == ',')
  844.     {
  845.         printf (",\n");
  846.         goto loop;
  847.     }
  848.     else
  849.         putchar ('\n');
  850.  
  851. done:
  852.     /* handle continuation lines */
  853.     if (ngets (buffer) != NULL)
  854.     {
  855.         line++;
  856.         if (buffer[0] == '\t')
  857.         {
  858.             cp = buffer;
  859.             goto loop;
  860.         }
  861.         else
  862.             ungets (buffer);
  863.     }
  864.     else
  865.         ungets ((char *) NULL);
  866.     
  867.     printf ("\t};\n");
  868.  
  869. #undef value
  870. #undef skipname
  871. }
  872.  
  873. /* header --- define sendmail headers */
  874.  
  875. header ()
  876. {
  877.     register char *cp = buffer + 1;
  878.     register int flags = 0;
  879.     register int conditional = 0;
  880.  
  881.     printf ("header\n\t");
  882.     if (*cp == '?')        /* header for mailers  with these flags */
  883.     {
  884.         flags++;
  885.         printf ("for (");
  886.         for (cp++; *cp != '?'; cp++)
  887.         {
  888.             printf ("%s", mflags (*cp));
  889.             if (cp[1] != '?')
  890.                 putchar (',');
  891.         }
  892.         printf (") {\n\t\t");
  893.         cp++;    /* skip final '?' */
  894.     }
  895.  
  896.     printf ("define (\"");
  897.     for (; *cp && ! isspace (*cp); cp++)
  898.         putchar (*cp);
  899.     printf ("\", \"");
  900.  
  901. body:
  902.     while (*cp)
  903.     {
  904.         switch (*cp) {
  905.         case '$':
  906.             switch (*++cp) {
  907.             case '?':
  908.                 printf ("ifset (%s, ", macro (*++cp));
  909.                 conditional++;
  910.                 break;
  911.             case '|':
  912.                 putchar (',');
  913.                 break;
  914.             case '.':
  915.                 putchar (')');
  916.                 conditional--;
  917.                 break;
  918.             default:
  919.                 printf ("${%s}", macro (*cp));
  920.                 break;
  921.             }
  922.             break;
  923.         default:
  924.             putchar (*cp);
  925.             break;
  926.         }
  927.         cp++;
  928.     }
  929.  
  930.     /* handle continuation lines */
  931.     if (ngets (buffer) != NULL)
  932.     {
  933.         line++;
  934.         if (buffer[0] == '\t')
  935.         {
  936.             printf ("\\\n");
  937.             cp = buffer + 1;
  938.             goto body;
  939.         }
  940.         else
  941.             ungets (buffer);
  942.     }
  943.     else
  944.         ungets ((char *) NULL);
  945.  
  946.     printf ("\");\n");
  947.  
  948.     if (flags)
  949.         printf ("\t};\n");
  950.  
  951.     if (conditional)
  952.         die ("header");
  953. }
  954.  
  955. /* option --- translate a sendmail option to an ease option */
  956.  
  957. option ()
  958. {
  959.     register char *name = buffer + 1, *value = buffer + 2;
  960.  
  961.     printf ("options\n\t");
  962.     if (*name == 'd')        /* delivery */
  963.         printf ("o_delivery = %s;\n", delivoption (*value));
  964.     else if (*name == 'e')        /* handling */
  965.         printf ("o_handling = %s;\n", handle_option (*value));
  966.     else
  967.         printf ("%s = \"%s\";\n", optionname (*name), value);
  968. }
  969.  
  970. /* trusted --- define the list of trusted users */
  971.  
  972. trusted ()
  973. {
  974.     register char *cp = buffer + 1;
  975.  
  976.     while (*cp)
  977.     {
  978.         if (isspace (*cp))
  979.             *cp = ',';
  980.         cp++;
  981.     }
  982.     printf ("trusted\n\t{ %s };\n", buffer+1);
  983. }
  984.  
  985. /* precedence --- define the precedence of a message class */
  986.  
  987. precedence ()
  988. {
  989.     register char *cp = buffer + 1;
  990.  
  991.     printf ("precedence\n\t");
  992.     for (; *cp && *cp != '='; cp++)
  993.         putchar (*cp);
  994.     printf (" = %s;\n", ++cp);
  995. }
  996.  
  997. /* other --- not a sendmail control line */
  998.  
  999. other ()
  1000. {
  1001.     printf ("%s\n", buffer);
  1002. }
  1003.  
  1004. die (routine)
  1005. char *routine;
  1006. {
  1007.     fprintf (stderr, "%s: malformed input line %d: fatal error\n",
  1008.             routine, line);
  1009.     exit (1);
  1010. }
  1011.  
  1012. /* macro --- return name for sendmail predefined macro */
  1013.  
  1014. char *macro (c)
  1015. char c;
  1016. {
  1017.     static char buf[2] = { '\0', '\0' };
  1018.  
  1019.     switch (c) {
  1020.     case 'a':    /* The origination date in Arpanet format */
  1021.         return ("m_odate");
  1022.  
  1023.     case 'b':    /* The current date in Arpanet format */
  1024.         return ("m_adate");
  1025.  
  1026.     case 'c':    /* The hop count */
  1027.         return ("m_hops");
  1028.  
  1029.     case 'd':    /* The date in UNIX (ctime) format */
  1030.         return ("m_udate");
  1031.  
  1032.     case 'e':    /* The SMTP entry message */
  1033.         return ("m_smtp");
  1034.  
  1035.     case 'f':    /* The sender (from) address */
  1036.         return ("m_saddr");
  1037.  
  1038.     case 'g':    /* The sender address relative to the recipient */
  1039.         return ("m_sreladdr");
  1040.  
  1041.     case 'h':    /* The recipient host */
  1042.         return ("m_rhost");
  1043.  
  1044.     case 'i':    /* The queue id */
  1045.         return ("m_qid");
  1046.  
  1047.     case 'j':    /* The official domain name for this site */
  1048.         return ("m_oname");
  1049.  
  1050.     case 'l':    /* The format of the UNIX from line */
  1051.         return ("m_ufrom");
  1052.  
  1053.     case 'n':    /* The name of the daemon (for error messages) */
  1054.         return ("m_daemon");
  1055.  
  1056.     case 'o':    /* The set of "operators" in addresses */
  1057.         return ("m_addrops");
  1058.  
  1059.     case 'p':    /* Sendmail's pid */
  1060.         return ("m_pid");
  1061.  
  1062.     case 'q':    /* The default format of sender address */
  1063.         return ("m_defaddr");
  1064.  
  1065.     case 'r':    /* Protocol used */
  1066.         return ("m_protocol");
  1067.  
  1068.     case 's':    /* Sender's host name */
  1069.         return ("m_shostname");
  1070.  
  1071.     case 't':    /* A numeric representation of the current time */
  1072.         return ("m_ctime");
  1073.  
  1074.     case 'u':    /* The recipient user */
  1075.         return ("m_ruser");
  1076.  
  1077.     case 'v':    /* The version number of sendmail */
  1078.         return ("m_version");
  1079.  
  1080.     case 'w':    /* The hostname of this site */
  1081.         return ("m_sitename");
  1082.  
  1083.     case 'x':    /* The full name of the sender */
  1084.         return ("m_sname");
  1085.  
  1086.     case 'y':    /* The id of the sender's tty */
  1087.         return ("m_stty");
  1088.  
  1089.     case 'z':    /* The home directory of the recipient */
  1090.         return ("m_rhdir");
  1091.  
  1092.     default:
  1093.         buf[0] = c;
  1094.         return (buf);
  1095.     }
  1096. }
  1097.  
  1098. #define docompat(val)    if (compat) goto warn; else return (val)
  1099.  
  1100. /* mflags --- convert sendmail mailer flags to ease names */
  1101.  
  1102. char *mflags (c)
  1103. char c;
  1104. {
  1105.     static char buf[2] = { '\0', '\0' };
  1106.  
  1107.     switch (c) {
  1108.     case 'f':    return ("f_ffrom");
  1109.     case 'r':    return ("f_rfrom");
  1110.     case 'S':    return ("f_noreset");
  1111.     case 'n':    return ("f_noufrom");
  1112.     case 'l':    return ("f_locm");
  1113.     case 's':    return ("f_strip"); 
  1114.     case 'm':    return ("f_mult");
  1115.     case 'F':    return ("f_from");
  1116.     case 'D':    return ("f_date");
  1117.     case 'M':    return ("f_mesg");
  1118.     case 'x':    return ("f_full");    
  1119.     case 'P':    return ("f_return");    
  1120.     case 'u':    return ("f_upperu");    
  1121.     case 'h':    return ("f_upperh");    
  1122.     case 'A':    return ("f_arpa");    
  1123.     case 'U':    return ("f_ufrom");    
  1124.     case 'e':    return ("f_expensive");    
  1125.     case 'X':    return ("f_dot");    
  1126.     case 'L':    return ("f_llimit");    
  1127.     case 'p':    return ("f_retsmtp");    
  1128.     case 'I':    return ("f_smtp");    
  1129.     case 'C':    return ("f_addrw");    
  1130.     case 'E':    docompat ("f_escape");
  1131.     default:
  1132.     warn:
  1133.         fprintf (stderr,
  1134.             "warning: non standard mailer flag '%c' on line %d\n",
  1135.                 c, line);
  1136.         buf[0] = c;
  1137.         return buf;
  1138.     }
  1139. }
  1140.  
  1141. /* optionname --- convert sendmail options to ease names */
  1142.  
  1143. char *optionname (c)
  1144. char c;
  1145. {
  1146.     static char buf[2] = { '\0', '\0' };
  1147.  
  1148.     switch (c) {
  1149.     case 'A':    return ("o_alias");
  1150.     case 'a':    return ("o_ewait");
  1151.     case 'B':    return ("o_bsub");
  1152.     case 'c':    return ("o_qwait");
  1153.     case 'd':    return ("o_delivery");
  1154.     case 'D':    return ("o_rebuild");
  1155.     case 'e':    return ("o_handling");
  1156.     case 'F':    return ("o_tmode");
  1157.     case 'f':    return ("o_usave");
  1158.     case 'g':    return ("o_gid");
  1159.     case 'H':    return ("o_fsmtp");
  1160.     case 'i':    return ("o_skipd");
  1161.     case 'L':    return ("o_slog");
  1162.     case 'm':    return ("o_rsend");
  1163.     case 'N':    return ("o_dnet");
  1164.     case 'o':    return ("o_hformat");
  1165.     case 'Q':    return ("o_qdir");
  1166.     case 'q':    docompat ("o_qfactor");
  1167.     case 'r':    return ("o_tread");
  1168.     case 'S':    return ("o_flog");
  1169.     case 's':    return ("o_safe");
  1170.     case 'T':    return ("o_qtimeout");
  1171.     case 't':    return ("o_timezone");
  1172.     case 'u':    return ("o_dmuid");
  1173.     case 'v':    return ("o_verbose");
  1174.     case 'W':    return ("o_wizpass");
  1175.     case 'x':    return ("o_loadq");
  1176.     case 'X':    return ("o_loadnc");
  1177.     case 'Y':    docompat ("o_newproc");
  1178.     case 'y':    docompat ("o_recipfactor");
  1179.     case 'Z':    docompat ("o_prifactor");
  1180.     case 'z':    docompat ("o_waitfactor");
  1181.     default:
  1182.     warn:
  1183.         fprintf (stderr,
  1184.             "warning: non standard option '%c' on line %d\n",
  1185.                 c, line);
  1186.         buf[0] = c;
  1187.         return buf;
  1188.     }
  1189. }
  1190.  
  1191. /* delivoption --- convert sendmail delivery option value to ease name */
  1192.  
  1193. char *delivoption (c)
  1194. char c;
  1195. {
  1196.     static char buf[2] = { '\0', '\0' };
  1197.  
  1198.     switch (c) {
  1199.     case 'i':    return ("d_interactive");
  1200.     case 'b':    return ("d_background");
  1201.     case 'q':    return ("d_queue");
  1202.     default:
  1203.         fprintf (stderr,
  1204.     "warning: non standard delivery option '%c' on line %d\n", c, line);
  1205.         buf[0] = c;
  1206.         return buf;
  1207.     }
  1208. }
  1209.  
  1210. /* handle_option --- convert sendmail handling option value to ease name */
  1211.  
  1212. char *handle_option (c)
  1213. char c;
  1214. {
  1215.     static char buf[2] = { '\0', '\0' };
  1216.  
  1217.     switch (c) {
  1218.     case 'p':    return ("h_print");
  1219.     case 'q':    return ("h_exit");
  1220.     case 'm':    return ("h_mail");
  1221.     case 'w':    return ("h_write");
  1222.     case 'e':    return ("h_mailz");
  1223.     default:
  1224.         fprintf (stderr,
  1225.     "warning: non standard handling option '%c' on line %d\n", c, line);
  1226.         buf[0] = c;
  1227.         return buf;
  1228.     }
  1229. }
  1230.  
  1231. /*
  1232.  * "buffered" i/o routines. These are necessary since
  1233.  * mail headers may have continuation lines, and we can't see if
  1234.  * a continuation line is there without getting it. If it isn't,
  1235.  * just put it back.
  1236.  */
  1237.  
  1238. int saved = 0;
  1239. char *saveb = NULL;
  1240.  
  1241. /* ngets --- get a line of input from either saved buffer or stdin */
  1242.  
  1243. char *ngets (bp)
  1244. char *bp;
  1245. {
  1246.     if (! saved)
  1247.         return (gets (bp));
  1248.  
  1249.     saved = 0;
  1250.     bp = saveb;
  1251.     saveb = NULL;
  1252.     return (bp);
  1253. }
  1254.  
  1255. /* ungets --- put a buffer back on the input, so to speak */
  1256.  
  1257. void ungets (bp)
  1258. char *bp;
  1259. {
  1260.     saved = 1;
  1261.     saveb = bp;
  1262.     line--;
  1263. }
  1264. SHAR_EOF
  1265. fi # end of overwriting check
  1266. #    End of shell archive
  1267. exit 0
  1268.  
  1269.  
  1270.